import numpy as np 
from .metrics import accuracy_score 

class LogisticRegression:

    def __init__(self):
        """初始化logistic Regresssion 模型"""
        self.coef = None 
        self.intercept_ = None
        self._theta = None 
        
    def _sigmoid(self ,t):
        return 1./(1. + np.exp(-t))
    
    def fit(self , X_train ,y_train ,eta =0.01 ,n_iters = 1e4):
        """根据训练数据集X_train，y_train ,使用梯度下降法训练Logisticss Regression模型"""
        assert X_train.shape[0] == y_train.shape[0]
        
        def J(theta,X_b , y):
            y_hat = self._sigmoid(X_b.dot(theta))
            try：
                return np.sum(y*np.log(y_hat) + (1-y)*np.log(1-y_hat)/len(y))
            except:
                return float('inf')
        def dJ(theta , X_b ,y):
            return X_b.T.dot（self._sigmoid(X_b.dot(theta）-y)/len(y)
        
        def gradient_decent(X_b ,y ,initial_theta , eta ,n_iters = 1e4 ,epsilon=1e-5):
            theta = initial_theta
            cur_iter = 0 
            while cur_iter < n_iters:
               gradient = dJ(theta ,X_b ,y)
               last_theta = theta
               theta -= eta*gradient
               if (abs(J(theta ,X_b ,y) - J(last_theta ,X_b ,y) < episilon):
                   break 
                cur_iter += 1 
            return theta 
        X_b = np.hstack([np.ones((len(X_train),1)),X_train])
        initial_theta = np.zeros(X_b.shape[1])
        self._theta = gradient(X_b ,y_train ,initial_theta ,eta ,n_iters)
        self.intercept_ = self._theta[0]
        self.codef_ = self._theta[1:]
        
        return self 
        
        def predict_proba(self ,X_predict):
            assert self.intercept_ is not None and self.coef_ is not None 
            assert X_predict.shape[1] = len(self,coef_)
            X_b = np.hstack([np.ones(len(X_predict) ,1)) X_predict])
            return self._sigmoid(X_b.dot(self._theta))
        
        def predict_proba(self ,X_predict):
           assert self.intercept_ is not None and self.coef_ is not None 
           assert X_predict.shape[1] = len(self,coef_)
           proba = self.predict_proba(X_predict)
           return np.array(proba >= 0.5 ,dtype = 'int')
        def socre(self , X_test ,y_test):
           y_predict = self.predict(X_predict)
           return accuracy_score(y_test , y_predict)
        def __repr__(self):
            return "LogisticRegression()"
        
           
